package controller;

import java.awt.Point;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;





import javax.swing.AbstractAction;



import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;


import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;






import model.AppModel;
import model.Folder;

import model.ModelException;
import view.AppView;




/**
 */
public class NavigationController {

	// Application model and view
	private AppModel model;
	private AppView view;
	private AppController appController;
	
	/**
	 * Constructor
	 * @param model
	 * @param view
	 * @param appController 
	 */
	public NavigationController(AppModel model, AppView view, AppController appController) {
		this.model = model;
		this.view = view;
		this.appController = appController;
		assignHandlersToEvents();
	}
	
	/**
	 * All possible actions for this controller
	 * 
	 * IMPORTANT: Always create a new method for every action,
	 * don't create any action logic directly under this function.
	 * This function is supposed to be the event listener, and actions
	 * should be separate functions.
	 */
	private void assignHandlersToEvents(){
	
		// Compose button click 
		view.getNavigation().getComposeBtn().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actionComposeMail(e);
			}
		});
	
		
		// Right click on any of the folders
		view.getNavigation().getFoldersList().addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed( MouseEvent e ){
				appController.getListingController().refreshListingView();
				if ( SwingUtilities.isRightMouseButton(e)){
					actionShowRightClickMenu(e);
				}	
			}
			@Override
			public void mouseReleased( MouseEvent e ){
				appController.getListingController().refreshListingView();
			}
		});	
		
	}
	
	
	/**
	 * Shows the right click menu when a folder is right clicked
	 * @param e
	 */
	protected void actionShowRightClickMenu(MouseEvent e) {
		
		// Selecting the currently right clicked folder
		JList foldersList = view.getNavigation().getFoldersList();
		Point p = e.getPoint();
		int index = foldersList.locationToIndex( p );
		ListSelectionModel selectionModel = foldersList.getSelectionModel();
		selectionModel.setSelectionInterval(index, index);
		
		// Check the folder name and return if it's one of the basic folders
		String clickedFolderName = view.getNavigation().getFolderNameAt(index);

		if (clickedFolderName.trim().equalsIgnoreCase("Inbox") ||
				clickedFolderName.trim().equalsIgnoreCase("Sent") ||
				clickedFolderName.trim().equalsIgnoreCase("Drafts") ||
				clickedFolderName.trim().equalsIgnoreCase("Outbox")){
			return;
		}
		
		// Create the popup menu
		JPopupMenu popup = new JPopupMenu("Folder options");
		JMenuItem deleteItem = new JMenuItem(new AbstractAction("Delete") {
		    public void actionPerformed(ActionEvent e) {
		        actionDeleteFolder();
		    }
		});
		JMenuItem renameItem = new JMenuItem(new AbstractAction("Rename") {
		    public void actionPerformed(ActionEvent e) {
		        actionRenameFolder();
		    }
		});
		JMenuItem createFolderItem = new JMenuItem(new AbstractAction("Create subfolder...") {
		    public void actionPerformed(ActionEvent e) {
		        actionCreateSubfolder();
		    }
		});
		
		// Add specific items
		if (!clickedFolderName.trim().equalsIgnoreCase("Root")){
			popup.add(deleteItem);
			popup.add(renameItem);
		}
		
		popup.add(createFolderItem);
		popup.show(e.getComponent(), e.getX(), e.getY());
	}

	/**
	 * Create new folder action
	 */
	protected void actionCreateSubfolder(){
		
		int i = view.getNavigation().getFoldersList().getSelectedIndex();
		int newFolderParentId = view.getNavigation().getFolderIdAt(i);

		while(true){
			
			String response = JOptionPane.showInputDialog("Enter a unique and valid name:");
			// Cancel
			if (response == null){
				break;
			}
			
			// Valid input, create subfolder 
			if (!response.trim().isEmpty() && !model.getUser().folderExists(response.toLowerCase())){
				try {
					model.getUser().createNewFolder(response, newFolderParentId);
					refreshNavigationFolders(response.trim());
				} catch (ModelException e) {
					System.out.println("Some error occcured, please try again");
				}
				break;
			}
		}
	}
	
	/**
	 * Rename folder action
	 */
	protected void actionRenameFolder() {
		
		int i = view.getNavigation().getFoldersList().getSelectedIndex();
		int folderId = view.getNavigation().getFolderIdAt(i);
		String currentName = view.getNavigation().getFolderNameAt(i).trim();
		
		String response = null;
		while(true){
			
			response =  JOptionPane.showInputDialog("Enter a new unique for folder '" + currentName +"'");

			// Cancel
			if (response == null){
				break;
			}
			
			// Valid input, rename 
			if (!response.trim().isEmpty() && !model.getUser().folderExists(response.toLowerCase()) && !response.equalsIgnoreCase(currentName) ){
				model.getUser().getFolder(folderId).setName(response);
				try {
					model.getUser().getFolder(folderId).save();
					refreshNavigationFolders(response.trim());
				} catch (ModelException e) {
					System.out.println("Some error occcured while saving, please try again");
				}
				break;
			}
		}
	}

	/**
	 * Resets the folders list and refreshes the navigation view
	 * @param selectAfterRefresh String
	 */
	protected void refreshNavigationFolders(String selectAfterRefresh){
		
		view.getNavigation().getFolders().clear();
		view.getNavigation().addNewFolder(0, 0, "Root", 0);
		for(Folder folder : model.getUser().getFolders()){
			if (folder.getParentId() == 0){
				addFolderToNavigation(folder); // Adding level 1 folders here
			}
		}
		
		// Select the folder after refresh
		if (selectAfterRefresh == null){
			view.getNavigation().setCurrentSelection("Inbox");
			model.setCurrentFolderId(model.getUser().getFolder("Inbox").getId());
		} else {
			view.getNavigation().setCurrentSelection(selectAfterRefresh);
			model.setCurrentFolderId(model.getUser().getFolder(model.getUser().getFolder(selectAfterRefresh).getId()).getId());
		}
		
		// Refresh listing
		appController.getListingController().refreshListingView();
		
		
	}
	
	/**
	 * Recursively adds all folders and their children to the navigation view
	 * @param folder
	 */
	private void addFolderToNavigation(Folder folder) {
		
		int level = model.getUser().getFolderLevel(folder.getId()) + 1;
		String name = folder.getName();
		int id = folder.getId();
		view.getNavigation().addNewFolder(level, id, name, folder.getEmails().size());
		for(Folder f :  model.getUser().getChildFolders(id) ){
			addFolderToNavigation(f);
		}
	}

	/**
	 * Delete folder action
	 */
	protected void actionDeleteFolder() {
		int option = JOptionPane.showConfirmDialog (null, "Are you sure you want to delete the selected folder?");
		if (option == JOptionPane.YES_OPTION ){
			
			int index = view.getNavigation().getFoldersList().getSelectedIndex();
			int folderId = view.getNavigation().getFolderIdAt(index);
			
			// Delete folder
			try {
				int parentId = model.getUser().getFolder(folderId).getParentId();
				model.getUser().deleteFolder(folderId);
				if (parentId == 0){
					refreshNavigationFolders("Inbox");
				} else {
					refreshNavigationFolders(model.getUser().getFolder(parentId).getName());
				}
				
				
			} catch (ModelException e) {
				System.out.println("Could not delete the folder : " + model.getUser().getFolderLevel(folderId));
			}
		}
	}
	

	/**
	 * Compose button click action
	 * @param e
	 */
	private void actionComposeMail(ActionEvent e){
		new ComposeMailController(null, model, appController); // 0 will be interpreted as new email
	}

	/**
	 * Calls the toNetworkLog method on the network log view
	 * 
	 * @param string
	 * @param string2
	 */
	public void notify(String messageType, String message) {
		view.getNavigation().notify(messageType, message);
	}
	
	/**
	 * Sets the network status to connected or disconnected
	 * @param connected
	 */
	public void setNetworkStatus(boolean connected){
		view.getNavigation().setConnectionStatus(connected);
	}

	/**
	 * Refreshes the currently selected navigation folder and all its emails
	 */
	public void refreshNavigationFolders() {
		refreshNavigationFolders(model.getCurrentFolderName());
	}
	
}
